﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


namespace _1945
{
    /// <summary>
    /// Struct for handling sprite data
    /// </summary>
    public struct Sprite
    {
        #region Struct Variables
        /// <summary>
        /// Defining if this sprite is animated or not.
        /// </summary>
        bool isAnimated;

        /// <summary>
        /// Rectangle for the current sprite being drawn.
        /// </summary>
        Rectangle spriteRectangle;

        /// <summary>
        /// Rectangle containing all sprites in the spritesheet.
        /// </summary>
        Rectangle animatedSpriteRectangle;

        /// <summary>
        /// Defining how long the switch to the next frame will be delayed (in ms).
        /// </summary>
        TimeSpan animatedSpriteNextFrameDelay;

        /// <summary>
        /// Defining how many frameswitches should be done per second.
        /// </summary>
        int animatedSpriteFramesPerSecond;

        /// <summary>
        /// When, measured as TimeSpan (Total elapsed GameTime), the last frame was switched to.
        /// </summary>
        TimeSpan animatedSpriteLastFrameSwitch;

        /// <summary>
        /// Defining for how long a sprite animation should play. So far only used for explosion animation.
        /// </summary>
        TimeSpan animatedSpriteTotalAnimationTime;
        
        /// <summary>
        /// When the animation started, measured as TimeSpan. So far only used for explosion animation.
        /// </summary>
        TimeSpan animatedSpriteAnimationStarted;

        /// <summary>
        /// Coordinates of the current frame in the spritesheet grid. Grid is defined by rectangle, and the number of rows and columns. 
        /// </summary>
        Vector2 animatedSpriteCurrentFrame;
        
        /// <summary>
        /// How many rows are in the spritesheet grid.
        /// </summary>
        int animatedSpriteRows;
        
        /// <summary>
        /// How many columns are in the spritesheet grid.
        /// </summary>
        int animatedSpriteColumns;

        /// <summary>
        /// The width of one sprite in the grid.
        /// </summary>
        int animatedSpriteWidth;
        
        /// <summary>
        /// The height of on sprite in the grid.
        /// </summary>
        int animatedSpriteHeight;
        #endregion

        #region Constructors
        /// <summary>
        /// Constructor used for a single sprite which is not animated
        /// </summary>
        /// <param name="spriteRectangle">Rectangle surrounding the sprite</param>
        public Sprite(Rectangle spriteRectangle)
        {
            this.isAnimated = false;
            this.spriteRectangle = spriteRectangle;
            this.animatedSpriteRectangle = Rectangle.Empty;
            this.animatedSpriteNextFrameDelay = TimeSpan.Zero;
            this.animatedSpriteFramesPerSecond = 0;
            this.animatedSpriteLastFrameSwitch = TimeSpan.Zero;
            this.animatedSpriteTotalAnimationTime = TimeSpan.Zero;
            this.animatedSpriteAnimationStarted = TimeSpan.Zero;
            this.animatedSpriteCurrentFrame = Vector2.Zero;
            this.animatedSpriteRows = 0;
            this.animatedSpriteColumns = 0;
            this.animatedSpriteWidth = 0;
            this.animatedSpriteHeight = 0;
        }
        /// <summary>
        /// Constructor for animated sprite
        /// </summary>
        /// <param name="animatedSpriteRectangle">Rectangle surrounding all the sprites being animated</param>
        /// <param name="animatedSpriteFramesPerSecond">How many times per second to perform a frame switch</param>
        /// <param name="animatedSpriteTotalAnimationTime">For how long the animation should play.</param>
        /// <param name="animatedSpriteRows">How many rows are in the spritesheet grid.</param>
        /// <param name="animatedSpriteColumns">How many columns are in the spritesheet grid.</param>
        public Sprite(Rectangle animatedSpriteRectangle, int animatedSpriteFramesPerSecond, TimeSpan animatedSpriteTotalAnimationTime, TimeSpan animatedSpriteAnimationStarted, int animatedSpriteRows, int animatedSpriteColumns)
        {
            this.isAnimated = true;
            this.animatedSpriteRectangle = animatedSpriteRectangle;
            this.animatedSpriteFramesPerSecond = animatedSpriteFramesPerSecond;
            this.animatedSpriteNextFrameDelay = new TimeSpan(10000000 / animatedSpriteFramesPerSecond);
            this.animatedSpriteLastFrameSwitch = TimeSpan.Zero;
            this.animatedSpriteTotalAnimationTime = animatedSpriteTotalAnimationTime;
            this.animatedSpriteAnimationStarted = animatedSpriteAnimationStarted;
            this.animatedSpriteCurrentFrame = Vector2.Zero;
            this.animatedSpriteRows = animatedSpriteRows;
            this.animatedSpriteColumns = animatedSpriteColumns;
            this.animatedSpriteWidth = (animatedSpriteRectangle.Width - (animatedSpriteColumns + 1) ) / animatedSpriteColumns; //width = width - borders / columns
            this.animatedSpriteHeight = (animatedSpriteRectangle.Height - (animatedSpriteRows + 1) ) / animatedSpriteRows; //heigt = height - borders / rows
            this.spriteRectangle = new Rectangle(animatedSpriteRectangle.X + 1, animatedSpriteRectangle.Y + 1, animatedSpriteWidth, animatedSpriteHeight);
        }
        #endregion

        #region Methods

        #region Getters
        public bool getIsAnimated()
        {
            return isAnimated;
        }

        public Rectangle getSpriteRectangle()
        {
            return spriteRectangle;
        }

        public int getWidth()
        {
            return spriteRectangle.Width;
        }

        public int getHeight()
        {
            return spriteRectangle.Height;
        }

        public bool getIsAnimationFinished(TimeSpan totalElapsed)
        {
            if (totalElapsed.Subtract(animatedSpriteAnimationStarted).CompareTo(animatedSpriteTotalAnimationTime) >= 0){
                return true;
            }
            else
            {
                return false;
            }
        }
        #endregion

        #region Setters

        /// <summary>
        /// Sets when animation started. So far only used for explosin animation.
        /// </summary>
        /// <param name="totalElapsed"></param>
        public void setAnimationStartedTime(TimeSpan totalElapsed)
        {
            animatedSpriteAnimationStarted = totalElapsed;
        }

        /// <summary>
        /// Swiches to next animated frame if enough time has passed
        /// </summary>
        /// <param name="totalElapsed">GameTime TotalElapsed</param>
        public void nextAnimatedFrame(TimeSpan totalElapsed)
        {
            if (totalElapsed.Subtract(animatedSpriteLastFrameSwitch).CompareTo(animatedSpriteNextFrameDelay) > 0)
            {
                /*
                 * Works today because animated sprites have either one row or one column 
                 */ 

                if (animatedSpriteCurrentFrame.X < animatedSpriteColumns)
                {
                    animatedSpriteCurrentFrame.X++;
                }
                else
                {
                    animatedSpriteCurrentFrame.X = 1;
                }

                if (animatedSpriteCurrentFrame.Y < animatedSpriteRows)
                {
                    animatedSpriteCurrentFrame.Y++;
                }
                else
                {
                    animatedSpriteCurrentFrame.Y = 1;
                }

                spriteRectangle.X = animatedSpriteRectangle.X + ((int)animatedSpriteCurrentFrame.X -1) * animatedSpriteWidth + (int)animatedSpriteCurrentFrame.X;
                spriteRectangle.Y = animatedSpriteRectangle.Y + ((int)animatedSpriteCurrentFrame.Y -1) * animatedSpriteHeight + (int)animatedSpriteCurrentFrame.Y;
                spriteRectangle.Width = animatedSpriteWidth;
                spriteRectangle.Height = animatedSpriteHeight;

                animatedSpriteLastFrameSwitch = totalElapsed;
            }

        }
        #endregion

        #endregion

    }
}
